﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Input;

using System.Diagnostics;
using System.Collections;
using System.Collections.ObjectModel;
using System.ComponentModel;
using SqlMiM.ReportingServices;
using System.Windows.Threading;
using SqlMiM.ReportingServices.SqlRs;
using SqlMiM.ReportingServices.Core;
using System.Windows.Forms;
using SqlMiM.Common.ViewModel;
using SqlMiM.Common.Commands;
using MvvmFoundation.Wpf;


namespace SqlMiM.ReportingServices.ReportExportPlugin
{
    public class ViewModel : ObservableObject
    {
        private ReportingService2005 rs;
        private BackgroundWorker workerWriterCatalog;
        private String webServiceUrl;
        private string outputDirectory;
        private bool isLoadingCatalog;
        private bool isFirstLoad;
        private bool isGenerating;
        private ObservableCollection<CatalogItemViewModel> catalog;
        private ObservableCollection<ResultWarningViewModel> resultWarnings;
        private RelayCommand refrehCatalogCommand;
        private RelayCommand navigateWebServiceCommand;
        private RelayCommand outputDirectoryCommand;
        private RelayCommand writeCatalogCommand;
       
        /// <summary>
        /// Constructor
        /// </summary>
        public ViewModel()
        {

            this.WebServiceUrl = RS.Current.GetReportingServicesWebServiceUrl();
            this.IsLoadingCatalog = false;
            this.IsFirstLoad = true;
            this.IsGenerating = false;
            this.ResultWarnings = new ObservableCollection<ResultWarningViewModel>();
        }


        /// <summary>
        /// Reporting Service Web Url;
        /// </summary>
        public String WebServiceUrl
        {
            get
            {
                return webServiceUrl;
            }
            set
            {
                webServiceUrl = value;
                this.RaisePropertyChanged("WebServiceUrl");
            }
        }

        /// <summary>
        /// OutPutDirectory 
        /// </summary>
        public string OutputDirectory
        {
            get { return outputDirectory; }
            set
            {
                outputDirectory = value;
                this.RaisePropertyChanged("OutputDirectory");
            }
        }


        /// <summary>
        /// Catalog is Loading
        /// </summary>
        public bool IsLoadingCatalog
        {
            get { return isLoadingCatalog; }
            set
            {
                isLoadingCatalog = value;
                this.RaisePropertyChanged("IsLoadingCatalog");
            }
        }


        /// <summary>
        /// View is loaded and no load on catalog has been made.
        /// </summary>
        public bool IsFirstLoad
        {
            get { return isFirstLoad; }
            set
            {
                isFirstLoad = value;
                this.RaisePropertyChanged("IsFirstLoad");
            }
        }

        /// <summary>
        /// View is generating files
        /// </summary>
        public bool IsGenerating
        {
            get { return isGenerating; }
            set
            {
                isGenerating = value;
                this.RaisePropertyChanged("IsGenerating");
            }
        }

        /// <summary>
        /// Items Catalog
        /// </summary>
        public ObservableCollection<CatalogItemViewModel> Catalog
        {
            get { return catalog; }
            set
            {
                catalog = value;
                this.RaisePropertyChanged("Catalog");
            }
        }


        /// <summary>
        /// Items Catalog
        /// </summary>
        public ObservableCollection<ResultWarningViewModel> ResultWarnings
        {
            get { return resultWarnings; }
            set
            {
                resultWarnings = value;
                this.RaisePropertyChanged("ResultWarnings");
            }
        }


        /// <summary>
        /// Returns a command that saves the customer.
        /// </summary>
        public ICommand NavigateWebServiceCommand
        {
            get
            {
                if (navigateWebServiceCommand == null)
                {
                    navigateWebServiceCommand = new RelayCommand(this.NavigateWebServiceUrl, this.CanNavigateWebServiceUrl);

                }
                return navigateWebServiceCommand;
            }
        }

        /// <summary>
        /// Returns a command that saves the customer.
        /// </summary>
        public ICommand RefrehCatalogCommand
        {
            get
            {
                if (refrehCatalogCommand == null)
                {
                    refrehCatalogCommand = new RelayCommand(this.RefreshCatalog, this.CanNavigateWebServiceUrl);

                }
                return refrehCatalogCommand;
            }
        }


        /// <summary>
        /// Returns a command that saves the customer.
        /// </summary>
        public ICommand OutputDirectoryCommand
        {
            get
            {
                if (outputDirectoryCommand == null)
                {
                    outputDirectoryCommand = new RelayCommand(this.GetOutputDirectoryCommand);

                }
                return outputDirectoryCommand;
            }
        }


        /// <summary>
        /// Write catalog (all checked items)
        /// </summary>
        public ICommand WriteCatalogCommand
        {
            get
            {
                if (writeCatalogCommand == null)
                {
                    writeCatalogCommand = new RelayCommand(this.WriteCatalog, this.CanWriteCatalog);

                }
                return writeCatalogCommand;
            }
        }





        /// <summary>
        /// Navigate to Web Service url
        /// </summary>
        /// <returns></returns>
        private void NavigateWebServiceUrl()
        {
            String navigateUri = this.WebServiceUrl;
            Process.Start(new ProcessStartInfo(navigateUri));
        }



        /// <summary>
        /// Check if WebService is filled
        /// </summary>
        /// <returns></returns>
        private bool CanNavigateWebServiceUrl()
        {
            return !string.IsNullOrEmpty(this.WebServiceUrl);
        }

        /// <summary>
        /// Load catalog
        /// </summary>
        private void RefreshCatalog()
        {
            this.IsLoadingCatalog = true;
            this.IsFirstLoad = false;

            var worker = new BackgroundWorker();

            worker.DoWork += (sender, e) =>
            {
                List<CatalogItemViewModel> lst = GetRecursiveCatalogItems(null, this.WebServiceUrl, "/");

                if (lst != null)
                {
                    this.Catalog = new ObservableCollection<CatalogItemViewModel>(lst);
                }

            };

            worker.RunWorkerCompleted += (sender, e) =>
            {
                this.IsLoadingCatalog = false;
            };

            worker.RunWorkerAsync();

        }

        /// <summary>
        /// Get All Items recursively
        /// </summary>
        private List<CatalogItemViewModel> GetRecursiveCatalogItems(CatalogItemViewModel parent, string url, string path)
        {
            List<CatalogItemViewModel> lst = new List<CatalogItemViewModel>();

            var items = RS.Current.GetChildrenItems(url, path);

            if (items != null)
            {
                foreach (var item in items)
                {
                    CatalogItemViewModel civm = new CatalogItemViewModel(item);
                    civm.Parent = parent;

                    // If it's a folder, go Recusive get sub items.
                    if (civm.Type == ItemTypeEnum.Folder)
                    {
                        var childs = GetRecursiveCatalogItems(civm, url, civm.Path);
                        if (childs != null)
                        {
                            civm.Childrens = new ObservableCollection<CatalogItemViewModel>(childs);
                        }
                    }

                    lst.Add(civm);
                }
            }

            return lst;
        }


        /// <summary>
        /// Get an output directory
        /// </summary>
        /// <returns></returns>
        private void GetOutputDirectoryCommand()
        {
            FolderBrowserDialog folderBrowserDialog = new FolderBrowserDialog();

            if (!String.IsNullOrEmpty(this.OutputDirectory))
            {
                folderBrowserDialog.SelectedPath = this.OutputDirectory;
            }

            if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
            {
                this.OutputDirectory = folderBrowserDialog.SelectedPath;
            }
        }


        /// <summary>
        /// Get if we can write catalog
        /// </summary>
        /// <returns></returns>
        private bool CanWriteCatalog()
        {
            // Cant generate when :
            //  Already in generating progress
            //  No catalog loaded
            //  Catalog empty
            return !this.IsGenerating && !this.IsLoadingCatalog && !String.IsNullOrEmpty(this.OutputDirectory) && this.Catalog != null && this.Catalog.Count > 0;
        }

        /// <summary>
        /// Write all checked items
        /// </summary>
        private void WriteCatalog()
        {

            this.IsGenerating = true;
            this.ResultWarnings = new ObservableCollection<ResultWarningViewModel>();

            workerWriterCatalog = new BackgroundWorker();
            workerWriterCatalog.WorkerReportsProgress = true;

            workerWriterCatalog.DoWork += AsyncWriteCatalog;

            workerWriterCatalog.ProgressChanged += AsyncWriteCatalog_ProgressChanged;

            workerWriterCatalog.RunWorkerCompleted += delegate(object sender, RunWorkerCompletedEventArgs e) 
            {
                this.IsGenerating = false;
                workerWriterCatalog.Dispose(); 
            };

            workerWriterCatalog.RunWorkerAsync();
        }

      

        private void AsyncWriteCatalog_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            // Add result to list ..
            this.ResultWarnings.Add(e.UserState as ResultWarningViewModel);

        }

        private void AsyncWriteCatalog(object sender, DoWorkEventArgs e)
        {
            // Reporting Service Instance
            var rs = new ReportingService2005();
            rs.Url = webServiceUrl;
            // Set Credentials
            rs.Credentials = System.Net.CredentialCache.DefaultCredentials;

            // Clear directory
            RS.Current.ClearDirectory(this.OutputDirectory);

            // Write all items
            RecurseWriteCatalog(rs, this.Catalog, e);
        }

        /// <summary>
        /// Write all catalog to file system
        /// </summary>
        private void RecurseWriteCatalog(ReportingService2005 rs, ObservableCollection<CatalogItemViewModel> subCatalog, DoWorkEventArgs e)
        {

            foreach (CatalogItemViewModel civm in subCatalog)
            {
                if (civm.IsChecked.HasValue && civm.IsChecked.Value)
                {
                    ResultWarning result = null;

                    switch (civm.Type)
                    {
                        case ItemTypeEnum.Folder:
                            result = RS.Current.ExportDirectory(rs, civm.Item, this.OutputDirectory);
                            break;
                        case ItemTypeEnum.DataSource:
                            result = RS.Current.ExportDataSource(rs, civm.Item, this.OutputDirectory);
                            break;
                        case ItemTypeEnum.LinkedReport:
                            break;

                        case ItemTypeEnum.Model:
                            result = RS.Current.ExportModel(rs, civm.Item, this.OutputDirectory);
                            break;
                        case ItemTypeEnum.Report:
                            result = RS.Current.ExportReport(rs, civm.Item, this.OutputDirectory);
                            break;
                        case ItemTypeEnum.Resource:
                            result = RS.Current.ExportRessource(rs, civm.Item, this.OutputDirectory);
                            break;
                        case ItemTypeEnum.Unknown:
                            break;
                        default:
                            break;
                    }

                    var r = new ResultWarningViewModel(result, civm.Type);

                    workerWriterCatalog.ReportProgress(0, r);

                }

                if (civm.Childrens != null && civm.Childrens.Count > 0)
                    RecurseWriteCatalog(rs, civm.Childrens, e);

            }
        }
    }
}
